package services

import (
	"colly/models"
	"context"
	"encoding/json"
	"github.com/PuerkitoBio/goquery"
	"github.com/gocolly/colly/v2"
	"github.com/gocolly/colly/v2/extensions"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func Offer(query string, proxyUrl, currency string, id int, db *gorm.DB, log *logrus.Logger) map[int]map[string]interface{} {
	uri := "https://www.g2g.com/checkout/buyNow/offerList?" + query
	htmlStr := ""
	c := colly.NewCollector(
		colly.MaxDepth(1),
		//colly.Debugger(&debug.LogDebugger{}),
	)
	extensions.RandomUserAgent(c)
	c.Limit(&colly.LimitRule{
		RandomDelay: 500 * time.Millisecond,
		Parallelism: 10,
	})
	cookie := &http.Cookie{
		Name:  "g2g_regional",
		Value: "%7B%22country%22%3A%22US%22%2C%22currency%22%3A%22" + currency + "%22%2C%22language%22%3A%22en%22%7D",
	}
	c.SetCookies(uri, []*http.Cookie{cookie})
	c.OnRequest(func(request *colly.Request) {
		request.Headers.Set("Accept-Language", "en,zh-TW;q=0.9,zh;q=0.8")
	})

	resp := RandomConn(proxyUrl, uri)
	defer resp.NetConn.Close()

	c.WithTransport(&http.Transport{
		DialContext: func(ctx context.Context, network, url string) (net.Conn, error) {
			return resp.NetConn, nil
		},
		MaxIdleConns:          100,
		IdleConnTimeout:       5 * time.Second,
		TLSHandshakeTimeout:   3 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	})
	data := make(map[int]map[string]interface{})
	c.OnResponse(func(response *colly.Response) {

		ret := make(map[string]interface{})
		json.Unmarshal(response.Body, &ret)
		htmlStr = ret["form"].(string)

		doc, _ := goquery.NewDocumentFromReader(strings.NewReader(htmlStr))
		//os.WriteFile("./temp/"+strconv.Itoa(id)+"_offer.html", []byte(htmlStr), 0777)
		format := "task_id=%d, proxy=%s, action=%s, sort=%d, offer_id=%s, offer=%s, level=%s, min=%s, stock=%s, amount=%s, currency=%s"
		tm := time.Now()
		doc.Find(".other_offer-desk-main-box").Each(func(iii int, ele *goquery.Selection) {
			sort := iii + 1
			if sort > 2 {
				return
			}
			hasMap := make(map[string]interface{})
			name := ele.Find(".seller__name-detail").Text()
			level := ele.Find(".seller_level-peronal").Text()
			level = strings.Replace(level, "Level ", "", -1)
			amount := ele.Find(".offer-price-amount").Text()
			cy := ele.Find(".offers_amount-currency-regional").Text()
			cy = strings.Split(cy, " ")[0]
			m := ele.Find(".offer__content-lower-items").Eq(3).Text()
			m = strings.Replace(m, "\t", "", -1)
			m = strings.Replace(m, "\n", "", -1)
			m = strings.TrimSpace(m)
			stock := ele.Find(".offer__content-lower-items").Eq(2).Text()
			stock = strings.Replace(stock, "\t", "", -1)
			stock = strings.Replace(stock, "\n", "", -1)
			stock = strings.TrimSpace(stock)
			hasMap["id"] = id
			hasMap["sort"] = sort
			hasMap["name"] = name
			hasMap["offer_id"], _ = ele.Attr("data-oid")
			hasMap["level"] = level
			hasMap["min"] = m
			hasMap["stock"] = stock
			hasMap["amount"] = amount
			hasMap["currency"] = currency
			data[id] = hasMap

			suggest := models.Suggest{}
			db.Where("gold_id = ? and sort = ? and currency = ?", id, sort, cy).Find(&suggest)
			price, _ := strconv.ParseFloat(amount, 64)

			action := "keep"
			if suggest.ID > 0 {
				if suggest.Price != price {
					action = "update"
				}
				updates := make(map[string]interface{})
				updates["price"] = price
				updates["offer"] = name
				updates["sort"] = sort
				updates["updated_at"] = tm
				updates["update_time"] = tm.Unix()
				db.Table(suggest.TableName()).Where("id = ?", suggest.ID).Updates(updates)
			} else {
				suggest.GoldId = id
				suggest.Sort = sort
				suggest.Offer = name
				suggest.Currency = cy
				suggest.CreatedAt = tm
				suggest.UpdatedAt = tm
				suggest.Price = price
				suggest.CreateTime = tm.Unix()
				suggest.UpdateTime = tm.Unix()
				db.Create(&suggest)
			}

			log.Infof(format, id, resp.Proxy.Name(), action, sort, hasMap["offer_id"], name, level, m, stock, amount, cy)

			history := models.History{}

			db.Table(history.TableName()).
				Where("gold_id = ? and sort = ? and price = ? and currency = ?", id, sort, suggest.Price, cy).
				Find(&history)

			if history.ID < 1 {
				history.GoldId = id
				history.Sort = sort
				history.Price = suggest.Price
				history.Offer = name
				history.Currency = cy
				history.CreatedAt = tm
				history.UpdatedAt = tm
				history.CreateTime = tm.Unix()
				history.UpdateTime = tm.Unix()
				db.Create(&history)
			}

		})
	})
	c.Visit(uri)
	return data
}
